package experiment;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.concurrent.Semaphore;

import stack.Stack;
import stack.StackWorker;
import stack.StackWorker.WorkerStat;

public class Experiment {

	private Stack stack_;
	private StackWorker[] workers_;
	
	//barrier permits - to know when all workers finished working - needed for the testing function
	private Semaphore permits_;

	//specific parameters to get from the user 
	private int workers_num_;
	private int actions_num_;
	private int pushs_num_;

	public void init() {
		init_params();
		init_stack();
		init_workers();
	}

	private void init_params() {
		String workersNum = null;
		String actionsNum = null;
		String pushNum = null;

		BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
				System.out));
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

		try {
			out.write("how many threads do you want?\n\n");
			out.flush();
			workersNum = in.readLine();

			out.write("how many action do you want each thread to make?\n\n");
			out.flush();
			actionsNum = in.readLine();
			out
					.write("how many threads do you want to push elements to the stack?\n\n");
			out.flush();
			pushNum = in.readLine();

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		workers_num_ = Integer.parseInt(workersNum);
		actions_num_ = Integer.parseInt(actionsNum);
		pushs_num_ = Integer.parseInt(pushNum);

	}

	public void run() {
		for (int i = 0; i < workers_.length; i++) {
			try {
				permits_.acquire();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			new Thread(workers_[i]).start();
		}
	}

	private void init_stack() {

		stack_ = new Stack(workers_num_);

	}

	private void init_workers() {
		
		workers_ = new StackWorker[workers_num_];
		permits_ = new Semaphore(workers_num_);
		int id;
		for (int i = 0; i < pushs_num_; i++) {
			id = i;
			workers_[i] = new StackWorker(stack_, id, StackWorker.PUSH,
					actions_num_, permits_);
			
		}

		for (int i = pushs_num_; i < workers_num_; i++) {
			id = i;
			workers_[i] = new StackWorker(stack_, id, StackWorker.POP,
					actions_num_, permits_);
		}
		for (int i = 0; i < workers_num_; i++) {
			workers_[i].init();			
		}

	}

	public void test() {
		for (int i = 0; i < workers_num_; i++) {
			try {
				permits_.acquire();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		WorkerStat statistics;

		for (int i = 0; i < workers_.length; i++) {
			statistics = workers_[i].getStat();
			System.out.println("for worker " + i
					+ "\nthe number of successes is: \n" + statistics.getSuccess()
					+ "\nand " + "the number of failures is\n"
					+ +statistics.getFailure());

		}

		System.out.println(stack_.size());

	}

}
